标签
spring
字数
2527 字
阅读时间
12 分钟
一、概述
Spring 容器和 SpringMVC 容器是父子容器.SpringMVC 容器中能够调用 Spring 容器的所有内容
1.1 运行原理
如果在 web.xml 中设置 DispatcherServlet 的<url-pattern>为/时,当用户发 起 请 求 , 请 求 一 个 控 制 器 , 首 先 会 执 行 DispatcherServlet. 由DispatcherServlet 调 用 HandlerMapping 的DefaultAnnotationHandlerMapping 解 析 URL, 解 析 后 调 用HandlerAdatper 组 件 的AnnotationMethodHandlerAdapter 调 用Controller 中的HandlerMethod.当 HandlerMethod 执行完成后会返回View,会被 ViewResovler 进行视图解析,解析后调用 jsp 对应的.class 文件并运行,最终把运行.class 文件的结果响应给客户端
二、核心知识
2.1 配置前端控制器
xml
<!-- Web.xml -->
<servlet>
<servlet-name>jqk</servlet-name> <!-- 自定义名字,与mapping对应 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet<servlet-class> <!-- 类的路径 -->
<init-param>
<param-name>contextConfigLocation</param-name> <!-- 定义参数,配值文件路径属性 -->
<param-value>classpath:springmvc.xml</param-value> <!-- 配置文件的路径 -->
</init-param>
<load-on-startup>1</load-on-startup> <!-- 启动时加载 -->
</servlet>
<servlet-mapping>
<servlet-name>jqk</servlet-name>
<url-pattern>/</url-pattern> <!-- 拦截的路径,/表示除jsp,其余全部拦截 -->
</servlet-mapping>2.2 springmvc配置
xml
<!-- springmvc.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<!-- 引入 xmlns:mvc 命名空间 -->
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描注解 -->
<context:component-scan base-package="com.bjsxt.controller"></context:component-scan>
<!-- 注解驱动 -->
<!-- org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandler Mapping -->
<!-- org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerA dapter -->
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property> <!-- 在转发前默认添加的前缀 -->
<property name="suffix" value=".jsp"></property> <!-- 默认添加的后缀 -->
</bean>
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 静态资源 -->
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
<mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
</beans>
<!-- 如果希望不执行自定义视图解析器,在方法返回值前面添加forward:或 redirect: -->2.3 添加字符编码过滤器
xml
<!-- Web.xml -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 过滤器的位置 -->
<init-param>
<param-name>encoding</param-name> <!-- 设值字符编码的属性名 -->
<param-value>utf-8</param-value> <!-- 设置字符编码格式 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern> <!-- 拦截路径,全部拦截 -->
</filter-mappin>2.4 参数接收
java
@Controller
public class DemoController {
//基本数据类型
@RequestMapping("demo")
//把内容写到方法(HandlerMethod)参数中,SpringMVC 只要有这个内 容,注入内容
//默认保证参数名称和请求中传递的参数名相同 value="参数名"
//如果请求参数名和方法参数名不对应使用@RequestParam()赋值
//如果方法参数是基本数据类型(不是封装类)可以通过 @RequestParam 设置默认值 defaultValue="默认值"
//如果强制要求必须有某个参数required=true
// @CookieValue(value="JSESSIONID",required=false) 可以获取cookie的值
public String demo(@RequestParam(value="name1",required=true) String name,@RequestParam(defaultValue="2") int age){
System.out.println("执行 demo"+" "+name+" "+age);
return "main.jsp";
}
// 对象类型
@RequestMapping("demo4")
//请求参数名和对象中属性名对应(get/set 方法)
// @RequestBody()可接收json格式数据
public String demo4(People peo){
return "main.jsp";
}
//在@RequestMapping 中一定要和请求格式对应
//{名称} 中名称自定义名称
//@PathVariable 获取@RequestMapping 中内容,默认按照 方法参数名称去寻找.
@RequestMapping("demo8/{id1}/{name}")
public String demo8(@PathVariable String name,@PathVariable("id1") int age){
System.out.println(name +" "+age);
return "/main.jsp";
}
}2.5 数据回显
数据执行出错后将原数据返回原页面 mvc会将对象属性默认赋值到请求作用域中,在jsp中EL表达式调用 其余可通过model调用
2.6 跳转方式
默认的调转方式是请求转发。
java
// 重定向
response.sendRedirect("testRetrunString");
// 转发
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);2.7 常用注解
java
//在方法上添加@ResponseBody(发放不进行转发到视图解析器,直接返回数据)
// 如果返回值满足 key-value 形式(对象或 map)
// 默认把响应头设置为 application/json;charset=utf-8 然后以输出流的形式响应给客户端
// 底层使用 Jackson 进行 json 转换,在项目中一定要导入 jackson 的 jar
//如果返回值不满足 key-value 把相应头设置为 text/html 然后以输出流的形式响应给客户端
// 如果返回值包含中文,出现中文乱码,在RequestMapping中设置charset的值
// @RequestMapping(value="demo12",produces="text/html; charset=utf-8")
@ResponseBody
// 获取指定请求头的值 value:请求头的名称
@RequestHeader(value="Accept")
// 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
// 出现在参数上,获取指定的数据给参数赋值。
// 属性:value:用于获取数据的key。
@ModelAttribute
// 在类上标识,用于多次执行控制器方法间的参数共享。
// 属性: value:用于指定存入的属性名称 type:用于指定存入的数据类型。
@SessionAttributes2.8 作用域传值
java
@RequestMapping("demo1")
public String demo1(HttpServletRequest abc,HttpSession sessionParam){
//request 作用域
abc.setAttribute("req", "req 的值");
//session 作用域
HttpSession session = abc.getSession();
session.setAttribute("session", "session 的值");
sessionParam.setAttribute("sessionParam", "sessionParam 的值");
//appliaction 作用域
ServletContext application = abc.getServletContext();
application.setAttribute("application","application 的值");
return "/index.jsp";
}
//把 map 中内容放在 request 作用域中
//spring 会对 map 集合通过 BindingAwareModelMap 进行实例化
@RequestMapping("demo2")
public String demo2(Map<String,Object> map){
System.out.println(map.getClass());
map.put("map","map 的值");
return "/index.jsp";
}
//把内容最终放入到 request 作用域中.
@RequestMapping("demo3")
public String demo3(Model model){
model.addAttribute("model", "model 的值");
return "/index.jsp";
}
@RequestMapping("demo4")
public ModelAndView demo4(){
//参数,跳转视图
ModelAndView mav = new ModelAndView("/index.jsp");
mav.addObject("mav", "mav 的值");
return mav;
}2.9 自定义拦截器
java
// 发送请求时被拦截器拦截,在控制器的前后添加额外功能 针对点是控制器方法.(对 Controller)
// 跟 AOP 区分开.AOP 在特定方法前后扩充(对 ServiceImpl)
// 拦截器只能拦截器 Controller
// Filter 可以拦截任何请求
// 创建拦截器
public class DemoInterceptor implements HandlerInterceptor {
//在进入控制器之前执行
//如果返回值为 false,阻止进入控制器
//控制代码
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("arg2:"+arg2);
System.out.println("preHandle");
return true;
}
//控制器执行完成,进入到 jsp 之前执行.
//日志记录.
//敏感词语过滤
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("往"+arg3.getViewName()+"跳转 ");
System.out.println("model 的值 "+arg3.getModel().get("model"));
String word = arg3.getModel().get("model").toString();
String newWord = word.replace("祖国", "**");
arg3.getModel().put("model", newWord);
// arg3.getModel().put("model", "修改后的内容");
System.out.println("postHandle");
}
//jsp 执行完成后执行
//记录执行过程中出现的异常.
//可以把异常记录到日志中
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println("afterCompletion"+arg3.getMessag e());
}
}配置拦截器
xml
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="com.bjsxt.interceptor.DemoInterceptor"></bean>
<!-- 不配置interceptor为拦截所有控制器,配置为拦截配置的url -->
<mvc:interceptor>
<mvc:mapping path="/demo"/>
<mvc:mapping path="/demo1"/>
<mvc:mapping path="/demo2"/>
<bean class="com.bjsxt.interceptor.DemoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>2.10 拦截器栈
- 多个拦截器同时生效时,组成了拦截器栈
- 顺序:先进后出
- 执行顺序和在 springmvc.xml 中配置顺序有关
- 设置先配置拦截器 A 在配置拦截器 B 执行顺序为
- preHandle(A) --> preHandle(B) --> 控制器方法 --> postHandle(B) --> postHanle(A) --> JSP --> afterCompletion(B) --> afterCompletion(A)
类型转换,以Date转换为例
方式一
xml
<!--
在 springmvc.xml 中配置,代码中不需要做任何修改
必须额外导入 joda-time.jar
时间类型 java.sql.Date
-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.Formattin gConversionServiceFactoryBean">
<property name="registerDefaultFormatters" value="false" /> <property name="formatters">
<set>
<bean class="org.springframework.format.number.NumberForm atAnnotationFormatterFactory" />
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.springframework.format.datetime.joda.Jod aTimeFormatterRegistrar">
<property name="dateFormatter">
<bean class="org.springframework.format.datetime.joda.Dat eTimeFormatterFactoryBean">
<property name="pattern" value="yyyy-MM-dd" />
</bean>
</property>
</bean>
</set>
</property>
</bean>方式二
java
//使 用 注 解 . 在 需 要 转 换 的 参 数 或 实 体 类 属 性 上 添 加
// Date 是 java.util.Date
//@DateTimeFormatter(pattern=”表达式”)
//使用 Date 参数接收
@RequestMapping("demo")
public String demo(@DateTimeFormat(pattern="yyyy-MM-dd") Date time){
System.out.println(time);
return "abc.jsp";
}
//在实体类中,通过在属性上添加注解,控制层直接通过实体类接收
@DateTimeFormat(pattern="yyyy/MM/dd")
private Date time;方式三
java
/**
* 自定义类型转换器
* 把字符串转换成日期的转换器
* @author rt
*/
public class StringToDateConverter implements Converter<String, Date>{
/**
* 进行类型转换的方法
*/
public Date convert(String source) {
// 判断
if(source == null) {
throw new RuntimeException("参数不能为空");
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// 解析字符串
Date date = df.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("类型转换错误");
}
}
}配置
xml
<!-- 在springmvc.xml配置文件中配置 -->
<!-- 注册自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!-- 开启Spring对MVC注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>2.11 数据校验
依赖
xml
// 添加jar包
hibernate-validator-4.3.0
jboss-logging-3.1.0
validation-api-1.0.0配置
xml
<!-- spring.xml -->
<!-- 校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- hibernate校验器-->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
<!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
<property name="validationMessageSource" ref="messageSource" />
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 资源文件名-->
<property name="basenames">
<list>
<value>classpath:CustomValidationMessages</value>
</list>
</property>
<!-- 资源文件编码格式 -->
<property name="fileEncodings" value="utf-8" />
<!-- 对资源文件内容缓存时间,单位秒 -->
<property name="cacheSeconds" value="120" />
</bean>注册校验器
xml
<!-- 注册校验器 -->
<mvc:annotation-driven conversion-service="conversionService" validator = "validator"></mvc:annotation-driven>使用
java
// 使用
//在属性上通过注解校验数据长度和是否为空
//错误信息是在CustomValidationMessages.properties中配置
@Size(min=1,max=30,message="{items.name}")
privte String name;
@NotNull(message="{items.name}")
private Date createtime;
// 在需要校验的pojo前边添加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
public String testValid(@Validated TestModel testModel,BindingResult bindingResult);2.12 全局异常处理
java
// 实现HandlerExceptionResolver 注册类
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
//处理异常
CustomException customException = null;
if(ex instanceof CustomException){
customException = (CustomException)ex;
}else{
customException = new CustomException("未知错误");
}
//错误信息
String message = customException.getMessage();
ModelAndView modelAndView = new ModelAndView();
//将错误信息传到页面
modelAndView.addObject("message", message);
//指向错误页面
modelAndView.setViewName("error");
return modelAndView;
}